home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.2 Applications 1996 May / SGI IRIX 6.2 Applications 1996 May.iso / dist / impr_dev.idb / usr / impressario / src / libimp / impOpen.c.z / impOpen.c
C/C++ Source or Header  |  1996-05-06  |  35KB  |  1,115 lines

  1. /**************************************************************************
  2.  *
  3.  *           Copyright (c)    1993 Silicon Graphics, Inc.
  4.  *            All Rights Reserved
  5.  *
  6.  *       THIS    IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SGI
  7.  *
  8.  * The copyright notice above does not evidence any actual of intended
  9.  * publication of such source code, and is an unpublished work by Silicon
  10.  * Graphics, Inc. This material contains CONFIDENTIAL INFORMATION that is
  11.  * the property of Silicon Graphics, Inc. Any use, duplication or
  12.  * disclosure not specifically authorized by Silicon Graphics is strictly
  13.  * prohibited.
  14.  *
  15.  * RESTRICTED RIGHTS LEGEND:
  16.  *
  17.  * Use, duplication or disclosure by the Government is subject to
  18.  * restrictions as set forth in subdivision (c)(1)(ii) of the Rights in
  19.  * Technical Data and Computer Software clause at DFARS 52.227-7013,
  20.  * and/or in similar or successor clauses in the FAR, DOD or NASA FAR
  21.  * Supplement. Unpublished - rights reserved under the Copyright Laws of
  22.  * the United States. Contractor is SILICON GRAPHICS, INC., 2011 N.
  23.  * Shoreline Blvd., Mountain View, CA 94039-7311
  24.  **************************************************************************
  25.  *
  26.  * File: impOpen.c
  27.  *
  28.  * Description: Image file open routines.
  29.  *
  30.  **************************************************************************/
  31.  
  32.  
  33. #ident "$Revision: 1.8 $"
  34.  
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40. #include <assert.h>
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <sys/mman.h>
  44. #include <fcntl.h>
  45. #include <unistd.h>
  46. #include <errno.h>
  47. #include <limits.h>
  48. #include "impI.h"
  49.  
  50.  
  51. /* Local functions */
  52.  
  53. static IMPImage* openImage(int fd, const char *fname, void *buf,
  54.             const char *mode, off_t offset, IMPCacheMode cache,
  55.             uint_t rasterType, uint_t dimension,
  56.             uint_t xSize, uint_t ySize,
  57.             uint_t numChannels, uint_t imageType, char *name);
  58. static int initRLE(IMPImage *image, int fd, void *buf, const char *mode,
  59.             off_t offset);
  60. static void errorCleanup(IMPImage *image, int fd, const char *fname);
  61. static int readData(int fd, void *fromBuf, void *toBuf,
  62.                 unsigned int amount, off_t offset);
  63. static int writeData(int fd, void *fromBuf, unsigned int amount, off_t offset);
  64. static void setCacheSize(IMPImage *image);
  65. static void getTags(IMPImage *image, int fd, void *buf, off_t offset, 
  66.             __uint32_t offsetTags);
  67.  
  68.  
  69. /**************************************************************************
  70.  *
  71.  * Function: impOpen
  72.  *
  73.  * Description: Opens an SGI image file specified by name for reading
  74.  *    or writing.
  75.  *
  76.  * Parameters: 
  77.  *    fname (I) - name of the file to open
  78.  *    mode (I) - "r" for read-only, "w" for write-only. Note that
  79.  *            read-write mode is not currently supported.
  80.  *
  81.  *    If the mode is "w" the following parameters must be specified.
  82.  *
  83.  *    rasterType (I) - raster encoding and bytes per pixel code
  84.  *            (e.g. IMP_RASTER_VERBATIM1)
  85.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  86.  *            2 for a bw image, and 3 for an rgb image.
  87.  *    xSize, ySize (I) - image size in pixels.
  88.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  89.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  90.  *            imp.h for additional choices.
  91.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  92.  *            Specify as NULL for a default name string.
  93.  *
  94.  * Return: Pointer to an SGI image file handle if the open is successful.
  95.  *    NULL is returned and IMPerrno is set if the open fails.
  96.  *
  97.  **************************************************************************/
  98. /* VARARGS */
  99.  
  100. IMPImage* impOpen(const char *fname, const char *mode, ...)
  101. {
  102.     va_list ap;
  103.     uint_t rasterType, dimension;
  104.     uint_t xSize, ySize;
  105.     uint_t numChannels, imageType;
  106.     char *name;
  107.  
  108.     /*
  109.      * Sanity check the inputs
  110.      */
  111.     assert(fname != NULL);
  112.     assert(mode != NULL);
  113.  
  114.     /*
  115.      * Get the arguments for the actual open function
  116.      */
  117.     if (*mode == 'w') {
  118.         va_start(ap, mode);
  119.         rasterType = va_arg(ap, uint_t);
  120.         dimension = va_arg(ap, uint_t);
  121.         xSize = va_arg(ap, uint_t);
  122.         ySize = va_arg(ap, uint_t);
  123.         numChannels = va_arg(ap, uint_t);
  124.         imageType = va_arg(ap, uint_t);
  125.         name = va_arg(ap, char*);
  126.         va_end(ap);
  127.     }
  128.  
  129.     /*
  130.      * Call the actual open function
  131.      */
  132.     return (openImage(0, fname, NULL, mode, 0, IMPNoCache, rasterType,
  133.             dimension, xSize, ySize, numChannels, imageType,
  134.             name));
  135. }
  136.  
  137.  
  138. /**************************************************************************
  139.  *
  140.  * Function: impOpenFd
  141.  *
  142.  * Description: Opens an SGI image file specified by descriptor for reading
  143.  *    or writing.
  144.  *
  145.  * Parameters: 
  146.  *    fd (I) - descriptor of the file.
  147.  *    mode (I) - "r" for read-only, "w" for write-only. Read-write
  148.  *            mode is not currently supported. Note that mode
  149.  *            must be compatible with the mode on fd.
  150.  *
  151.  *    If the mode is "w" the following parameters must be specified.
  152.  *
  153.  *    rasterType (I) - raster encoding and bytes per pixel code
  154.  *            (e.g. IMP_RASTER_VERBATIM1)
  155.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  156.  *            2 for a bw image, and 3 for an rgb image.
  157.  *    xSize, ySize (I) - image size in pixels.
  158.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  159.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  160.  *            imp.h for additional choices.
  161.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  162.  *            Specify as NULL for a default name string.
  163.  *
  164.  * Return: Pointer to an SGI image file handle if the open is successful.
  165.  *    NULL is returned and IMPerrno is set if the open fails.
  166.  *
  167.  **************************************************************************/
  168. /* VARARGS */
  169.  
  170. IMPImage* impOpenFd(int fd, const char *mode, ...)
  171. {
  172.     va_list ap;
  173.     uint_t rasterType, dimension;
  174.     uint_t xSize, ySize;
  175.     uint_t numChannels, imageType;
  176.     char *name;
  177.     struct stat sbuf;
  178.  
  179.     /*
  180.      * Sanity check the inputs
  181.      */
  182.     assert(mode != NULL);
  183.  
  184.     /*
  185.      * Verify that the file descriptor is valid and
  186.      * is seekable. To test seekability we check that an
  187.      * lseek succeeds and that the descriptor is not connected
  188.      * to a tty. It turns out that the lseek test succeeds for
  189.      * a tty so we add the isatty test.
  190.      */
  191.     if (fstat(fd, &sbuf) < 0)
  192.     _impReturnErrorPtr(IMP_ERR_BADFD);
  193.     if (lseek(fd, 0L, SEEK_CUR) < 0 || isatty(fd))
  194.     _impReturnErrorPtr(IMP_ERR_SEEK);
  195.  
  196.     /*
  197.      * Get the arguments for the actual open function
  198.      */
  199.     if (*mode == 'w') {
  200.         va_start(ap, mode);
  201.         rasterType = va_arg(ap, uint_t);
  202.         dimension = va_arg(ap, uint_t);
  203.         xSize = va_arg(ap, uint_t);
  204.         ySize = va_arg(ap, uint_t);
  205.         numChannels = va_arg(ap, uint_t);
  206.         imageType = va_arg(ap, uint_t);
  207.         name = va_arg(ap, char*);
  208.         va_end(ap);
  209.     }
  210.  
  211.     /*
  212.      * Call the actual open function
  213.      */
  214.     return (openImage(fd, NULL, NULL, mode, 0, IMPNoCache, rasterType,
  215.             dimension, xSize, ySize, numChannels, imageType,
  216.             name));
  217. }
  218.  
  219.  
  220. /**************************************************************************
  221.  *
  222.  * Function: impOpenBuf
  223.  *
  224.  * Description: Opens an SGI image file contained in a memory buffer for
  225.  *    reading or writing.
  226.  *
  227.  *    The user must not deallocate the buffer until all libimp operations
  228.  *    are completed and impClose has been called.
  229.  *
  230.  * Parameters: 
  231.  *    buf (I) - pointer to buffer hodling image
  232.  *    mode (I) - "r" for read-only, "w" for write-only. Read-write
  233.  *            mode is not currently supported. Note that mode
  234.  *            must be compatible with the mode on fd.
  235.  *
  236.  *    If the mode is "w" the following parameters must be specified.
  237.  *
  238.  *    rasterType (I) - raster encoding and bytes per pixel code
  239.  *            (e.g. IMP_RASTER_VERBATIM1)
  240.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  241.  *            2 for a bw image, and 3 for an rgb image.
  242.  *    xSize, ySize (I) - image size in pixels.
  243.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  244.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  245.  *            imp.h for additional choices.
  246.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  247.  *            Specify as NULL for a default name string.
  248.  *
  249.  * Return: Pointer to an SGI image file handle if the open is successful.
  250.  *    NULL is returned and IMPerrno is set if the open fails.
  251.  *
  252.  **************************************************************************/
  253. /* VARARGS */
  254.  
  255. IMPImage* impOpenBuf(void *buf, const char *mode, ...)
  256. {
  257.     uint_t rasterType, dimension;
  258.     uint_t xSize, ySize;
  259.     uint_t numChannels, imageType;
  260.     char *name;
  261.  
  262.     /*
  263.      * Sanity check the inputs
  264.      */
  265.     assert(buf != NULL);
  266.     assert(mode != NULL);
  267.  
  268.     /*
  269.      * Image write to a buffer not currently supported. This is because
  270.      * it is not possible to know up front how big the buffer should be
  271.      * before you write into it. This is due to RLE compressarion possibly
  272.      * making the file larger than its dimensions would suggest.
  273.      */
  274.     if (*mode == 'w')
  275.     _impReturnErrorPtr(IMP_ERR_NOWRITE);
  276.  
  277.     /*
  278.      * Call the actual open function
  279.      */
  280.     return (openImage(0, NULL, buf, mode, 0, _IMPBufDirect, rasterType,
  281.             dimension, xSize, ySize, numChannels, imageType,
  282.             name));
  283. }
  284.  
  285.  
  286. /**************************************************************************
  287.  *
  288.  * Function: impOpenExt
  289.  *
  290.  * Description: Opens an SGI image file specified by name for reading
  291.  *    or writing. The Ext (extended) form of the impOpen function
  292.  *    allows an offset into the image file to be specified. In addition
  293.  *    the image may be cached in memory when in read-only mode.
  294.  *
  295.  * Parameters: 
  296.  *    fname (I) - name of the file to open
  297.  *    mode (I) - "r" for read-only, "w" for write-only. Note that
  298.  *            read-write mode is not currently supported.
  299.  *    offset (I) - number of bytes from the start of the file where
  300.  *            reading or writing is to begin.
  301.  *    cache (I) - if IMPCache and mode is read-only, the entire image
  302.  *            will be cached in memory. If IMPNoCache or
  303.  *            mode is write-only, no caching is done.
  304.  *
  305.  *    If the mode is "w" the following parameters must be specified.
  306.  *
  307.  *    rasterType (I) - raster encoding and bytes per pixel code
  308.  *            (e.g. IMP_RASTER_VERBATIM1)
  309.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  310.  *            2 for a bw image, and 3 for an rgb image.
  311.  *    xSize, ySize (I) - image size in pixels.
  312.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  313.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  314.  *            imp.h for additional choices.
  315.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  316.  *            Specify as NULL for a default name string.
  317.  *
  318.  * Return: Pointer to an SGI image file handle if the open is successful.
  319.  *    NULL is returned and IMPerrno is set if the open fails.
  320.  *
  321.  **************************************************************************/
  322. /* VARARGS */
  323.  
  324. IMPImage* impOpenExt(const char *fname, const char *mode, off_t offset,
  325.                     IMPCacheMode cache, ...)
  326. {
  327.     va_list ap;
  328.     uint_t rasterType, dimension;
  329.     uint_t xSize, ySize;
  330.     uint_t numChannels, imageType;
  331.     char *name;
  332.  
  333.     /*
  334.      * Sanity check the inputs
  335.      */
  336.     assert(fname != NULL);
  337.     assert(mode != NULL);
  338.  
  339.     /*
  340.      * Get the arguments for the actual open function
  341.      */
  342.     if (*mode == 'w') {
  343.         va_start(ap, cache);
  344.         rasterType = va_arg(ap, uint_t);
  345.         dimension = va_arg(ap, uint_t);
  346.         xSize = va_arg(ap, uint_t);
  347.         ySize = va_arg(ap, uint_t);
  348.         numChannels = va_arg(ap, uint_t);
  349.         imageType = va_arg(ap, uint_t);
  350.         name = va_arg(ap, char*);
  351.         va_end(ap);
  352.  
  353.     /*
  354.      * We do not do caching for image writes
  355.      */
  356.     cache = IMPNoCache;
  357.     }
  358.  
  359.     /*
  360.      * Call the actual open function
  361.      */
  362.     return (openImage(0, fname, NULL, mode, offset, cache, rasterType,
  363.             dimension, xSize, ySize, numChannels, imageType,
  364.             name));
  365. }
  366.  
  367.  
  368. /**************************************************************************
  369.  *
  370.  * Function: impOpenFdExt
  371.  *
  372.  * Description: Opens an SGI image file specified by descriptor for reading
  373.  *    or writing. The Ext (extended) form of the impOpenFd function
  374.  *    allows an offset into the image file to be specified. In addition
  375.  *    the image may be cached in memory when in read-only mode.
  376.  *
  377.  * Parameters: 
  378.  *    fd (I) - descriptor of the file.
  379.  *    mode (I) - "r" for read-only, "w" for write-only. Read-write
  380.  *            mode is not currently supported. Note that mode
  381.  *            must be compatible with the mode on fd.
  382.  *    offset (I) - number of bytes from the start of the file where
  383.  *            reading or writing is to begin.
  384.  *    cache (I) - if IMPCache and mode is read-only, the entire image
  385.  *            will be cached in memory. If IMPNoCache or
  386.  *            mode is write-only, no caching is done.
  387.  *
  388.  *    If the mode is "w" the following parameters must be specified.
  389.  *
  390.  *    rasterType (I) - raster encoding and bytes per pixel code
  391.  *            (e.g. IMP_RASTER_VERBATIM1)
  392.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  393.  *            2 for a bw image, and 3 for an rgb image.
  394.  *    xSize, ySize (I) - image size in pixels.
  395.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  396.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  397.  *            imp.h for additional choices.
  398.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  399.  *            Specify as NULL for a default name string.
  400.  *
  401.  * Return: Pointer to an SGI image file handle if the open is successful.
  402.  *    NULL is returned and IMPerrno is set if the open fails.
  403.  *
  404.  **************************************************************************/
  405. /* VARARGS */
  406.  
  407. IMPImage* impOpenFdExt(int fd, const char *mode, off_t offset,
  408.                         IMPCacheMode cache, ...)
  409. {
  410.     va_list ap;
  411.     uint_t rasterType, dimension;
  412.     uint_t xSize, ySize;
  413.     uint_t numChannels, imageType;
  414.     char *name;
  415.     struct stat sbuf;
  416.  
  417.     /*
  418.      * Sanity check the inputs
  419.      */
  420.     assert(mode != NULL);
  421.  
  422.     /*
  423.      * Verify that the file descriptor is valid and
  424.      * is seekable. To test seekability we check that an
  425.      * lseek succeeds and that the descriptor is not connected
  426.      * to a tty. It turns out that the lseek test succeeds for
  427.      * a tty so we add the isatty test.
  428.      */
  429.     if (fstat(fd, &sbuf) < 0)
  430.     _impReturnErrorPtr(IMP_ERR_BADFD);
  431.     if (lseek(fd, 0L, SEEK_CUR) < 0 || isatty(fd))
  432.     _impReturnErrorPtr(IMP_ERR_SEEK);
  433.  
  434.     /*
  435.      * Get the arguments for the actual open function
  436.      */
  437.     if (*mode == 'w') {
  438.         va_start(ap, cache);
  439.         rasterType = va_arg(ap, uint_t);
  440.         dimension = va_arg(ap, uint_t);
  441.         xSize = va_arg(ap, uint_t);
  442.         ySize = va_arg(ap, uint_t);
  443.         numChannels = va_arg(ap, uint_t);
  444.         imageType = va_arg(ap, uint_t);
  445.         name = va_arg(ap, char*);
  446.         va_end(ap);
  447.  
  448.     /*
  449.      * We do not do caching for image writes
  450.      */
  451.     cache = IMPNoCache;
  452.     }
  453.  
  454.     /*
  455.      * Call the actual open function
  456.      */
  457.     return (openImage(fd, NULL, NULL, mode, offset, cache, rasterType,
  458.             dimension, xSize, ySize, numChannels, imageType,
  459.             name));
  460. }
  461.  
  462.  
  463. /**************************************************************************
  464.  *
  465.  * Function: impOpenBufExt
  466.  *
  467.  * Description: Opens an SGI image file specified in a memory buffer for
  468.  *    reading or writing. The Ext (extended) form of the impOpenBuf function
  469.  *    allows an offset into the image file to be specified.
  470.  *
  471.  *    The user must not deallocate the buffer until all libimp operations
  472.  *    are completed and impClose has been called.
  473.  *
  474.  * Parameters: 
  475.  *    buf (I) - buffer containing the image
  476.  *    mode (I) - "r" for read-only, "w" for write-only. Read-write
  477.  *            mode is not currently supported. Note that mode
  478.  *            must be compatible with the mode on fd.
  479.  *    offset (I) - number of bytes from the start of the file where
  480.  *            reading or writing is to begin.
  481.  *
  482.  *    If the mode is "w" the following parameters must be specified.
  483.  *
  484.  *    rasterType (I) - raster encoding and bytes per pixel code
  485.  *            (e.g. IMP_RASTER_VERBATIM1)
  486.  *    dimesnion (I) - image dimension. Set this to 1 for a colormap,
  487.  *            2 for a bw image, and 3 for an rgb image.
  488.  *    xSize, ySize (I) - image size in pixels.
  489.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  490.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  491.  *            imp.h for additional choices.
  492.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  493.  *            Specify as NULL for a default name string.
  494.  *
  495.  * Return: Pointer to an SGI image file handle if the open is successful.
  496.  *    NULL is returned and IMPerrno is set if the open fails.
  497.  *
  498.  **************************************************************************/
  499. /* VARARGS */
  500.  
  501. IMPImage* impOpenBufExt(void *buf, const char *mode, off_t offset, ...)
  502. {
  503.     uint_t rasterType, dimension;
  504.     uint_t xSize, ySize;
  505.     uint_t numChannels, imageType;
  506.     char *name;
  507.  
  508.     /*
  509.      * Sanity check the inputs
  510.      */
  511.     assert(buf != NULL);
  512.     assert(mode != NULL);
  513.  
  514.     /*
  515.      * Image write to a buffer not currently supported. This is because
  516.      * it is not possible to know up front how big the buffer should be
  517.      * before you write into it. This is due to RLE compressarion possibly
  518.      * making the file larger than its dimensions would suggest.
  519.      */
  520.     if (*mode == 'w')
  521.     _impReturnErrorPtr(IMP_ERR_NOWRITE);
  522.  
  523.     /*
  524.      * Call the actual open function
  525.      */
  526.     return (openImage(0, NULL, buf, mode, offset, _IMPBufDirect, rasterType,
  527.             dimension, xSize, ySize, numChannels, imageType,
  528.             name));
  529. }
  530.  
  531.  
  532. /*
  533.  =========================================================================
  534.             LOCAL FUNCTIONS
  535.  =========================================================================
  536. */
  537.  
  538.  
  539. /**************************************************************************
  540.  *
  541.  * Function: openImage
  542.  *
  543.  * Description: Performs the actual job of opening an SGI Image file.
  544.  *    The file may be specified as either a filename or file
  545.  *    descriptor.
  546.  *
  547.  * Parameters: 
  548.  *    fd (I) - descriptor of open file
  549.  *    fname (I) - name of the file to open. If NULL, fd or buf will be used.
  550.  *    buf (I) - buffer to open. If NULL, fd or fname will be used.
  551.  *    mode (I) - "r" for read-only, "w" for write-only. Note that if
  552.  *            fd is specified it must have permissions compatible
  553.  *            with mode.
  554.  *    offset (I) - offset into file to begin reading or writing.
  555.  *    cache (I) - if IMPCache and read-only, entire image is cached in
  556.  *            memory.
  557.  *
  558.  *    The following are ignored if open is "r"
  559.  *
  560.  *    rasterType (I) - raster encoding and bytes per pixel code
  561.  *            (e.g. IMP_RASTER_VERBATIM1)
  562.  *    dimension (I) - image dimension. Set this to 1 for a colormap,
  563.  *            2 for a bw image, and 3 for an rgb image.
  564.  *    xSize, ySize (I) - image size in pixels.
  565.  *    numChannels (I) - 1 for colormap or bw image, 3 for rgb.
  566.  *    imageType (I) - IMP_IMAGE_NORMAL for a regular image. See
  567.  *            imp.h for additional choices.
  568.  *    name (I) - optional image name. IMP_NAME_MAX characters maximum.
  569.  *            Specify as NULL for a default name string.
  570.  *
  571.  * Return: Pointer to an SGI image file handle if the open is successful.
  572.  *    NULL is returned and IMPerrno is set if the open fails.
  573.  *
  574.  **************************************************************************/
  575.  
  576. static IMPImage* openImage(int fd, const char *fname, void *buf,
  577.             register const char *mode,
  578.             off_t offset, IMPCacheMode cache,
  579.             uint_t rasterType, uint_t dimension,
  580.             uint_t xSize, uint_t ySize,
  581.             uint_t numChannels, uint_t imageType, char *name)
  582. {
  583.     register IMPImage *image;
  584.     __uint32_t offsetTags;
  585.  
  586.     /*
  587.      * Sanity check the mode setting
  588.      */
  589.     if (mode[1] == '+')
  590.     _impReturnErrorPtr(IMP_ERR_READWRITE);
  591.  
  592.     /*
  593.      * Allocate space for the header that we will return as the
  594.      * image handle if all goes well.
  595.      */
  596.     if ((image = (IMPImage*)calloc(1, sizeof(IMPImage))) == NULL)
  597.     _impReturnErrorPtr(IMP_ERR_MEMALLOC);
  598.  
  599.     /*
  600.      * WRITE: If we are writing, we initialize and write the header
  601.      */
  602.     if (*mode == 'w') {
  603.     /*
  604.      * Create the file if necessary
  605.      */
  606.     if (fname)
  607.         fd = creat(fname, 0666);
  608.     if (fd < 0) {
  609.         IMPerrno = errno;
  610.         errorCleanup(image, fd, fname);
  611.         _impReturnErrorPtr(IMPerrno);
  612.     }
  613.  
  614.     /*
  615.      * Initialize disk archived header fields and write the header
  616.      */
  617.     impMagic(image) = IMP_MAGIC;
  618.     impRasterType(image) = (ushort_t)rasterType;
  619.     impImageType(image) = imageType;
  620.     impMinValue(image) = SHRT_MAX;
  621.     impMaxValue(image) = SHRT_MIN;
  622.     image->wastebytes = 0;
  623.     image->dorev = 0;
  624.     (void)strncpy(image->name, (name)? name: "no name", IMP_NAME_MAX);
  625.     image->name[IMP_NAME_MAX - 1] = '\0';
  626.     impXSize(image) = (ushort_t)xSize;
  627.     impYSize(image) = 1;
  628.     impNumChannels(image) = 1;
  629.     if (dimension > 1)
  630.         impYSize(image) = (ushort_t)ySize;
  631.     if (dimension > 2)
  632.         impNumChannels(image) = (ushort_t)numChannels;
  633.     if (impNumChannels(image) == 1) {
  634.         impDimension(image) = 2;
  635.         if (impYSize(image) == 1)
  636.         impDimension(image) = 1;
  637.     } else
  638.         impDimension(image) = 3;
  639.     impTags(image) = (IMPTag *) NULL;
  640.     if (writeData(fd, image, sizeof(IMPImage), offset) !=
  641.       sizeof(IMPImage)) {
  642.         IMPerrno = errno;
  643.         errorCleanup(image, fd, fname);
  644.         _impReturnErrorPtr(IMPerrno);
  645.     }
  646.     }
  647.     /*
  648.      * READ: If we are reading, we read the header and do sanity checks
  649.      */
  650.     else {
  651.     int retv;
  652.  
  653.     /*
  654.      * Open the file if necessary
  655.      */
  656.     if (buf == NULL) {
  657.         if (fname)
  658.             fd = open(fname, O_RDONLY);
  659.         if (fd < 0) {
  660.             IMPerrno = errno;
  661.             errorCleanup(image, fd, fname);
  662.             _impReturnErrorPtr(IMPerrno);
  663.         }
  664.     }
  665.  
  666.     /*
  667.      * Read the image header. Note that we need to reinit the
  668.      * pointers in the structure since reading the disk header
  669.      * can change them from NULL.
  670.      */
  671.     retv = readData(fd, buf, image, sizeof(IMPImage), offset);
  672.     image->tmpbuf = NULL;
  673.     image->rowstart = NULL;
  674.     image->rowsize = NULL;
  675.     if (retv != sizeof(IMPImage)) {
  676.         IMPerrno = errno;
  677.         errorCleanup(image, fd, fname);
  678.         _impReturnErrorPtr(IMPerrno);
  679.     }
  680.  
  681.     /*
  682.      * Determine if this image file needs byte swapping.
  683.      * If it does, we need to swap the bytes of the disk
  684.      * relevant portions of the header we just read.
  685.      */
  686.     if (_impSwapShort(impMagic(image)) == IMP_MAGIC) {
  687.         image->dorev = 1;
  688.         _impSwapHeader(image);
  689.     } else
  690.         image->dorev = 0;
  691.  
  692.     /*
  693.      * Verify that this is an SGI Image file
  694.      */
  695.     if (impMagic(image) != IMP_MAGIC) {
  696.         errorCleanup(image, fd, fname);
  697.         _impReturnErrorPtr(IMP_ERR_BADMAGIC);
  698.     }
  699.     if (!impIsRLE(image) && !impIsVERBATIM(image)) {
  700.         errorCleanup(image, fd, fname);
  701.         _impReturnErrorPtr(IMP_ERR_BADRASTER);
  702.     }
  703.     if (impImageType(image) > IMP_IMAGE_COLORMAP) {
  704.         errorCleanup(image, fd, fname);
  705.         _impReturnErrorPtr(IMP_ERR_BADIMAGE);
  706.     }
  707.     }
  708.  
  709.     /*
  710.      * Are there extension tags?
  711.      */
  712.     if(readData(fd, buf, &offsetTags, sizeof(__uint32_t),
  713.       offset + IMP_TAG_PTR_OFFSET) == sizeof(__uint32_t)) {
  714.     if(image->dorev)
  715.         _impSwapLongs(&offsetTags, sizeof(long));
  716.     if (offsetTags != 0)
  717.         getTags(image, fd, buf, offset, offsetTags);
  718.     }
  719.  
  720.  
  721.     /*
  722.      * If the raster encoding is RLE, there is some additional
  723.      * processing
  724.      */
  725.     if (impIsRLE(image)) {
  726.     if (initRLE(image, fd, buf, mode, offset) < 0) {
  727.         errorCleanup(image, fd, fname);
  728.         _impReturnErrorPtr(IMPerrno);
  729.     }
  730.     }
  731.  
  732.     /*
  733.      * Allocate scratch storage for row operations
  734.      */
  735.     if ((image->tmpbuf = _impBufferAlloc(image)) == NULL) {
  736.     errorCleanup(image, fd, fname);
  737.     _impReturnErrorPtr(IMP_ERR_MEMALLOC);
  738.     }
  739.  
  740.     /*
  741.      * Initialize image header fields used in core
  742.      */
  743.     image->file = (buf) ? -1: fd;
  744.     image->flags = (*mode == 'w') ? _IOWRT: _IOREAD;
  745.     image->cnt = 0;
  746.     image->ptr = NULL;
  747.     image->base = NULL;
  748.     image->x = image->y = image->z = 0;
  749.     image->offset = offset + _IMP_TABLES_START;
  750.     image->start = offset;
  751.     image->cache = cache;
  752.     image->cachebuf = NULL;
  753.     image->cachesize = 0;
  754.     image->cacheoffset = 0;
  755.  
  756.     /*
  757.      * If we are performing image caching, set up the cache. 
  758.      * Otherwise prepare for disk based processing.
  759.      */
  760.     if (cache != IMPNoCache) {
  761.     /*
  762.      * We cache only the image data. This requires that we add an
  763.      * offset when determining our position in the data since the cache
  764.      * will not necessarily be aligned with the start of the file.
  765.      */
  766.     setCacheSize(image);
  767.  
  768.     /*
  769.      * If we are heap caching, allocate space and read in the data
  770.      */
  771.     if (cache == IMPHeapCache) {
  772.         if ((image->cachebuf = malloc(image->cachesize)) == NULL) {
  773.         errorCleanup(image, fd, fname);
  774.         _impReturnErrorPtr(IMP_ERR_MEMALLOC);
  775.         }
  776.         if (readData(image->file, buf, image->cachebuf, image->cachesize,
  777.                 image->cacheoffset) != image->cachesize) {
  778.                 IMPerrno = errno;
  779.         free(image->cachebuf);
  780.                 errorCleanup(image, fd, fname);
  781.                 _impReturnErrorPtr(IMPerrno);
  782.         }
  783.     }
  784.     /*
  785.      * If we are memory mapping, simply do the mmap
  786.      */
  787.     else if (cache == IMPMapCache) {
  788.         image->cachebuf = mmap(NULL, image->cachesize, PROT_READ,
  789.                 MAP_SHARED, image->file, image->cacheoffset);
  790.         if (image->cachebuf == (void*)-1) {
  791.                 IMPerrno = errno;
  792.                 errorCleanup(image, fd, fname);
  793.                 _impReturnErrorPtr(IMPerrno);
  794.         }
  795.     }
  796.     /*
  797.      * If we have a user buffer we just point to that
  798.      */
  799.     else if (cache == _IMPBufDirect) {
  800.         image->cachebuf = ((char*)buf) + image->cacheoffset;
  801.     }
  802.     }
  803.     /*
  804.      * Seek to start of image row table
  805.      */
  806.     else {
  807.         if (lseek(image->file, image->offset, SEEK_SET) < 0) {
  808.             IMPerrno = errno;
  809.             errorCleanup(image, fd, fname);
  810.             _impReturnErrorPtr(IMPerrno);
  811.         }
  812.     }
  813.  
  814.     return image;
  815. }
  816.  
  817.  
  818. /**************************************************************************
  819.  *
  820.  * Function: initRLE
  821.  *
  822.  * Description: Initializes the Run Length Encoding tables. We allocate
  823.  *    space for the tables. If we are writing the image, we initialize
  824.  *    the tables to known values. If we are reading the image, we seek
  825.  *    to the tables, read them and swap their bytes, if necessary.
  826.  *
  827.  * Parameters: 
  828.  *    image (I) - pointer to an image structure
  829.  *    fd (I) - image file descriptor
  830.  *    buf (I) - image buffer
  831.  *    mode (I) - read/write flag
  832.  *    offset (I) - image start offset
  833.  *
  834.  * Return: 0 if successful. -1 if errors have been encountered. IMPerrno
  835.  *    will be set by this function if errors have occurred.
  836.  *
  837.  **************************************************************************/
  838.  
  839. static int initRLE(IMPImage *image, int fd, void *buf,
  840.                 const char *mode, off_t offset)
  841. {
  842.     int rleTableSize;
  843.  
  844.     /*
  845.      * Allocate RLE location and size tables
  846.      */
  847.     rleTableSize = impYSize(image) * impNumChannels(image) * sizeof(__int32_t);
  848.     image->rowstart = (__uint32_t*)malloc(rleTableSize);
  849.     image->rowsize = (__int32_t*)malloc(rleTableSize);
  850.     if (image->rowstart == NULL || image->rowsize == NULL)
  851.     _impReturnError(IMP_ERR_MEMALLOC);
  852.     image->rleend = _IMP_TABLES_START + (rleTableSize << 1);
  853.  
  854.     /*
  855.      * WRITE: If we are writing, we initialize the tables
  856.      */
  857.     if (*mode == 'w') {
  858.     register int nTable = rleTableSize / sizeof(__int32_t);
  859.     register int i;
  860.  
  861.     for (i = 0; i < nTable; i++) {
  862.         image->rowstart[i] = 0;
  863.         image->rowsize[i] = -1;
  864.     }
  865.     }
  866.     /*
  867.      * READ: If we are reading, read the tables and swap bytes
  868.      * if necessary.
  869.      */
  870.     else {
  871.     if (readData(fd, buf, image->rowstart, rleTableSize,
  872.                 offset + _IMP_TABLES_START) != rleTableSize)
  873.         _impReturnError(errno);
  874.     if (readData(fd, buf, image->rowsize, rleTableSize,
  875.                 offset + _IMP_TABLES_START + rleTableSize)
  876.                 != rleTableSize)
  877.         _impReturnError(errno);
  878.     if (image->dorev) {
  879.         _impSwapLongs(image->rowstart, rleTableSize);
  880.         _impSwapLongs((__uint32_t*)image->rowsize, rleTableSize);
  881.     }
  882.     }
  883.  
  884.     return 0;
  885. }
  886.  
  887.  
  888. /**************************************************************************
  889.  *
  890.  * Function: errorCleanup
  891.  *
  892.  * Description: Ensures that we deallocate storage before we return due
  893.  *    to an error condition.
  894.  *
  895.  * Parameters: 
  896.  *    image (I) - pointer to an allocated image structure.
  897.  *    fd (I) - file descriptor of image file.
  898.  *    fname (I) - name of image file or NULL.
  899.  *
  900.  * Return: none
  901.  *
  902.  **************************************************************************/
  903.  
  904. static void errorCleanup(IMPImage *image, int fd, const char *fname)
  905. {
  906.     /*
  907.      * Close the image file if we opened it and it is valid
  908.      */
  909.     if (fname && (fd >= 0))
  910.     (void)close(fd);
  911.  
  912.     /*
  913.      * Free the allocated image structure fields and the
  914.      * image structure itself
  915.      */
  916.     if (image->rowstart)
  917.     free(image->rowstart);
  918.     if (image->rowsize)
  919.     free(image->rowsize);
  920.     if (image->tmpbuf)
  921.     free(image->tmpbuf);
  922.     free(image);
  923. }
  924.  
  925.  
  926. /**************************************************************************
  927.  *
  928.  * Function: readData
  929.  *
  930.  * Description: A wrapper around the read function that allows us to
  931.  *    specify an offset from the beginning of the file.
  932.  *
  933.  * Parameters: 
  934.  *    fd (I) - file descriptor from which to read
  935.  *    fromBuf (I) - if not NULL this buffer will be read instead of fd
  936.  *    toBuf (I) - buffer to fill with read data
  937.  *    amount (I) - number of bytes to read
  938.  *    offset (I) - offset from beginning of file where data is to be read.
  939.  *
  940.  * Return: Number of bytes read if no error or -1 if error.
  941.  *
  942.  **************************************************************************/
  943.  
  944. static int readData(int fd, void *fromBuf, void *toBuf,
  945.                     unsigned int amount, off_t offset)
  946. {
  947.     if (fromBuf) {
  948.     memcpy(toBuf, &((char*)fromBuf)[offset], amount);
  949.     return (int)amount;
  950.     }
  951.  
  952.     if (lseek(fd, offset, SEEK_SET) == -1)
  953.         return -1;
  954.     return read(fd, toBuf, amount);
  955. }
  956.  
  957.  
  958. /**************************************************************************
  959.  *
  960.  * Function: writeData
  961.  *
  962.  * Description: A wrapper around the write function that allows us to
  963.  *    specify an offset from the beginning of the file.
  964.  *
  965.  * Parameters: 
  966.  *    fd (I) - file descriptor from which to read
  967.  *    fromBuf (I) - buffer to write
  968.  *    amount (I) - number of bytes to write
  969.  *    offset (I) - offset from beginning of file where data is to be written.
  970.  *
  971.  * Return: Number of bytes written if no error or -1 if error.
  972.  *
  973. **************************************************************************/
  974.  
  975. static int writeData(int fd, void *fromBuf, unsigned int amount, off_t offset)
  976. {
  977.     if (lseek(fd, offset, SEEK_SET) == -1)
  978.     return -1;
  979.     return write(fd, fromBuf, amount);
  980. }
  981.  
  982.  
  983. /**************************************************************************
  984.  *
  985.  * Function: setCacheSize
  986.  *
  987.  * Description: Sets the cache size and offset fields of the specified
  988.  *    image structure. For heap cacheing the cache size is calculated
  989.  *    as the size of the raw image data. In this case the cache offset
  990.  *    is the position of the start of the iamge data (i.e. table start
  991.  *    plus size of tables). If we are memory mapping the file the offset
  992.  *    is the closest page and the cache size is the amount of raw image
  993.  *    data plus the slop due to page alignment.
  994.  *
  995.  * Parameters: 
  996.  *    image (I) - SGI image structure
  997.  *
  998.  * Return: Size in bytes to store the entire image.
  999.  *
  1000.  **************************************************************************/
  1001.  
  1002. static void setCacheSize(IMPImage *image)
  1003. {
  1004.     /*
  1005.      * If the image is RLE compressed, sum the rowsize array to get the
  1006.      * total image data size. The offset is the max header size and the
  1007.      * size of the tables.
  1008.      */
  1009.     if (impIsRLE(image)) {
  1010.         int i;
  1011.         int num = impYSize(image) * impNumChannels(image);
  1012.  
  1013.     for (i = 0, image->cachesize = 0; i < num; i++)
  1014.         image->cachesize += image->rowsize[i];
  1015.     image->cacheoffset = image->start + _IMP_TABLES_START +
  1016.                         2 * num * sizeof(__int32_t);
  1017.     }
  1018.     /*
  1019.      * Otherwise the image is verbatim and we calculate the size directly
  1020.      */
  1021.     else {
  1022.     image->cachesize = impXSize(image) * impYSize(image) *
  1023.                 impNumChannels(image) * impRasterBPP(image);
  1024.     image->cacheoffset = image->start + _IMP_TABLES_START;
  1025.     }
  1026.  
  1027.     /*
  1028.      * If we are memory mapping the file we need to align the cache on
  1029.      * a page boundary so we adjust the cache offset and size accordingly.
  1030.      */
  1031.     if (image->cache == IMPMapCache) {
  1032.     int adjust = image->cacheoffset % getpagesize();
  1033.     image->cachesize += adjust;
  1034.     image->cacheoffset -= adjust;
  1035.     }
  1036. }
  1037.  
  1038.  
  1039. /**************************************************************************
  1040.  *
  1041.  * Function: getTags
  1042.  *
  1043.  * Description: Reads any extension tags that are appended to the image.
  1044.  *              If tags are present, the image structure is intialized to
  1045.  *        point to them.
  1046.  *
  1047.  * Parameters: 
  1048.  *    image (I) - SGI image structure
  1049.  *    fd (I) - image file descriptor
  1050.  *    buf (I) - image buffer
  1051.  *      offset (I)  - start of image data on file
  1052.  *    offsetTags (I) - where the tags begin
  1053.  *
  1054.  * Return: nothing
  1055.  *
  1056.  **************************************************************************/
  1057.  
  1058. static void getTags(IMPImage *image, int fd, void *buf, off_t offset,
  1059.   __uint32_t offsetTags)
  1060. {
  1061.     IMPTag    dummyTag;
  1062.     char    test[4];
  1063.     char    *magic="tags";
  1064.     off_t    localOffset;
  1065.  
  1066.     localOffset = offset + offsetTags;
  1067.     if(readData(fd, buf, &dummyTag.header, sizeof(IMPTagHeader),
  1068.       localOffset) != sizeof(IMPTagHeader)) 
  1069.       return;
  1070.     localOffset += sizeof(IMPTagHeader);
  1071.     if(readData(fd, buf, test, 4, localOffset) != 4) 
  1072.       return;
  1073.     localOffset += 4; 
  1074.     if(image->dorev) {
  1075.     _impSwapLongs((__uint32_t *) &dummyTag.header,
  1076.         sizeof(IMPTagHeader));
  1077.     _impSwapLongs((__uint32_t *) test, 1);
  1078.     }
  1079.  
  1080.     if( (dummyTag.header.tagname != IMP_TAG_FIRST_TAG) ||
  1081.     (dummyTag.header.length != strlen(magic)) ||
  1082.     strncmp(test, magic, 4) != 0) {
  1083.     /* We don't actually have any extension tags */
  1084.     impTags(image) = (IMPTag *) 0;
  1085.     } else {
  1086.     IMPTag    **prevTagPtr, *pTag;
  1087.  
  1088.     prevTagPtr =  &image->tags;
  1089.     pTag = malloc(sizeof(IMPTag));
  1090.     if(readData(fd, buf, &pTag->header, sizeof(IMPTagHeader),
  1091.       localOffset) != sizeof(IMPTagHeader))
  1092.           return;
  1093.     /* XXX is there a byte swapping problem here? */
  1094.     localOffset += sizeof(IMPTagHeader);
  1095.  
  1096.     while(pTag->header.tagname != IMP_TAG_LAST_TAG) {
  1097.         pTag->data = malloc(pTag->header.length);
  1098.         *prevTagPtr = pTag;
  1099.         if(readData(fd, buf, pTag->data, pTag->header.length, localOffset)
  1100.             != pTag->header.length) 
  1101.         return;
  1102.         localOffset += pTag->header.length;
  1103.         prevTagPtr = &pTag->next;
  1104.         pTag = malloc(sizeof(IMPTag));
  1105.         if(readData(fd, buf, pTag, sizeof(IMPTagHeader), localOffset) !=
  1106.           sizeof(IMPTagHeader))
  1107.         return;
  1108.         localOffset += sizeof(IMPTagHeader);
  1109.     }
  1110.     /* We don't actually want to save the final null pointer */
  1111.     *prevTagPtr = (IMPTag *) NULL;
  1112.     free(pTag);
  1113.     }
  1114. }
  1115.